package modeller.databasedesignmodel.servicedemand.transaction.proceduralstatement;

import exceptions.NoIndexOnAttributesException;
import modeller.databasedesignmodel.Attribute;
import modeller.databasedesignmodel.DatabaseDesign;
import modeller.databasedesignmodel.relation.Relation;
import modeller.databasedesignmodel.relation.index.AbstractTableIndex;
import modeller.databasedesignmodel.relation.index.HeapIndex;
import modeller.databasedesignmodel.servicedemand.IServiceDemand;
import modeller.databasedesignmodel.servicedemand.transaction.sqlquery.calculatorfetcher.ISQLQueryServiceDemandCalculatorFetcher;
import modeller.databasedesignmodel.servicedemand.transaction.sqlquery.demandFetcher.ISQLQueryServiceDemandCalculator;
import modeller.databasedesignmodel.transaction.*;

import java.util.HashSet;

/**
 * Created by:  Jason Ye
 * Date:        25/03/2012
 * Time:        17:58
 */
public class ProceduralStatementCalculatorVisitor implements IProceduralStatementServiceDemandCalculator {

    protected DatabaseDesign design;
    protected ISQLQueryServiceDemandCalculatorFetcher sqlQueryCalculatorFetcher;
    protected HeapIndex defIndex;

    public ProceduralStatementCalculatorVisitor(DatabaseDesign d, ISQLQueryServiceDemandCalculatorFetcher sqlQueryCalculatorFetcher) {
        this.design = d;
        this.sqlQueryCalculatorFetcher = sqlQueryCalculatorFetcher;
        defIndex = new HeapIndex();
    }

    @Override
    public IServiceDemand calculate(Loop loop) {

        int numIterations = loop.getNumIterations();
        IProceduralStatement contents = loop.getLoopContents();
        return new LoopServiceDemand(contents.acceptCalculation(this), numIterations);
    }

    @Override
    public IServiceDemand calculate(SQLQuerySequence stmt) {

        SQLQuerySequenceServiceDemand demandChain = new SQLQuerySequenceServiceDemand();

        for (ISQLQuery query : stmt.getStatementSequence()) {

            // calculate service demand and add to sequencedemand
            demandChain.addDemand(calculate(query));

        }

        return demandChain;

    }


    private IServiceDemand calculate(ISQLQuery query) {

        //find correct calculator
        //find correct index for query
        Relation r = query.getRelation().getFirst();
        HashSet<Attribute> blah = query.getRelation().getSecond();
        ISQLQueryServiceDemandCalculator queryServiceDemandCalculator;
        try {
            // find appropriate index for query
            AbstractTableIndex index = r.getIndexWithAttributes(blah);
            queryServiceDemandCalculator = index.offerCalculator(sqlQueryCalculatorFetcher);
        } catch (NoIndexOnAttributesException e) {
            //no index found, use default heap calculator
            queryServiceDemandCalculator = defIndex.offerCalculator(sqlQueryCalculatorFetcher);
        }
        // calculate service demand for the query using obtained calculator
        return query.acceptCalculation(queryServiceDemandCalculator);

    }

    @Override
    public IServiceDemand calculate(Branch branch) {

        IServiceDemand trueDem = branch.getTrueStatement().acceptCalculation(this);
        IServiceDemand falseDem = branch.getFalseStatement().acceptCalculation(this);

        return new BranchServiceDemand(trueDem, falseDem, branch.getTrueBranchExecProbability());
    }




}
